package cz.vutbr.fit.dnacompress.encoding;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;

import org.biojava.bio.BioException;
import org.biojava.utils.ParserException;

import cz.vutbr.fit.dnacompress.events.AlignEvent;

/**
 * abstractni koder zapouzdrujici praci s kodery
 */
public abstract class AbstractCoder {	
	
	/**
	 * identifikator koderu pro hlavicku souboru
	 */
	protected int coderID;
	
	/**
	 * dve verze tabulky poctu pro snadnejsi manipulaci
	 */
	protected HashMap<String, Integer> countTableEncode = null;
	protected HashMap<Integer, String> countTableDecode = null;
	
	/**
	 * @return the coderID
	 */
	public int getCoderID() {
		return coderID;
	}

	/**
	 * @param coderID the coderID to set
	 */
	public void setCoderID(int coderID) {
		this.coderID = coderID;
	}
	
	/**
	 * Hromadny konstruktor na zaklade identifikatoru koderu ( pro prikazovou radku a dekodovani z hlavicky)
	 * 
	 * @param ID
	 * @param countTableFileName
	 * @return AbstractCoder
	 * @throws BioException
	 * @throws IOException
	 * @throws ParserException
	 */
	public static AbstractCoder getClass( int ID, String countTableFileName) 
		throws BioException, IOException, ParserException {
		
		AbstractCoder ac = null;
		switch( ID) {
			case 1:
				ac = new StringCoder();
				break;
			case 2:
				ac = new EliasCoder( countTableFileName);
				break;
			case 3:
				ac = new RiceCoder( countTableFileName);
				break;
			case 4:
				ac = new HuffmanCoder( countTableFileName);
				break;
			default:
				throw new IllegalArgumentException( ID + " is not valid encoding options!");
		}
		return ac;
	}

	/**
	 * Nastaqveni tabulky poctu
	 * 
	 * @param tableFileName
	 * @throws IOException
	 * @throws ParserException
	 */
	public void setCountTables( String tableFileName) throws IOException, ParserException {
		
		countTableEncode = new HashMap<String, Integer>();
		countTableDecode = new HashMap<Integer, String>();
		
		BufferedReader bf = new BufferedReader( new FileReader( tableFileName));
		
		String line = null;
		while((line = bf.readLine()) != null) {
			
			String[] splitStrings = line.split("\\|");
			if( splitStrings.length != 2) {
				throw new ParserException( "Wrong column count in countTable!");
			}
			countTableEncode.put( splitStrings[0], Integer.parseInt( splitStrings[1]));
			countTableDecode.put( Integer.parseInt( splitStrings[1]), splitStrings[0]);
		}
	}
	
	/**
	 * kodovani eventu
	 * 
	 * @param events
	 * @return byte[]
	 */
	abstract public byte[] encode( List<AlignEvent> events);
	
	/**
	 * dekodovani eventu
	 * 
	 * @param is
	 * @return List<AlignEvent>
	 * @throws IOException
	 * @throws ParserException
	 */
	abstract public List<AlignEvent> decode( InputStream is) throws IOException, ParserException;
}
